package com.zg.datapush.health;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zg.datapush.constant.DataPushConstants;
import com.zg.common.core.dao.datapush.dao.DpPushRecordDao;
import com.zg.common.core.dao.datapush.dao.DpPushTaskDao;
import com.zg.common.core.dao.datapush.entity.DpPushRecord;
import com.zg.common.core.dao.datapush.entity.DpPushTask;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * 数据推送健康检查
 * @author zg
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class DataPushHealthIndicator implements HealthIndicator {

    private final DpPushTaskDao pushTaskDao;
    private final DpPushRecordDao pushRecordDao;

    @Override
    public Health health() {
        try {
            Health.Builder builder = Health.up();

            // 检查任务状态
            checkTaskStatus(builder);

            // 检查推送记录状态
            checkPushRecordStatus(builder);

            // 检查系统负载
            checkSystemLoad(builder);

            return builder.build();

        } catch (Exception e) {
            log.error("健康检查失败", e);
            return Health.down()
                    .withDetail("error", e.getMessage())
                    .build();
        }
    }

    /**
     * 检查任务状态
     */
    private void checkTaskStatus(Health.Builder builder) {
        try {
            // 统计启用的任务数量
            long enabledTaskCount = pushTaskDao.count(
                new LambdaQueryWrapper<DpPushTask>()
                    .eq(DpPushTask::getStatus, DataPushConstants.TASK_STATUS_ENABLED)
            );

            // 统计定时任务数量
            long scheduledTaskCount = pushTaskDao.count(
                new LambdaQueryWrapper<DpPushTask>()
                    .eq(DpPushTask::getStatus, DataPushConstants.TASK_STATUS_ENABLED)
                    .eq(DpPushTask::getScheduleType, DataPushConstants.SCHEDULE_TYPE_CRON)
            );

            builder.withDetail("tasks.enabled", enabledTaskCount)
                   .withDetail("tasks.scheduled", scheduledTaskCount);

        } catch (Exception e) {
            log.warn("检查任务状态失败", e);
            builder.withDetail("tasks.error", e.getMessage());
        }
    }

    /**
     * 检查推送记录状态
     */
    private void checkPushRecordStatus(Health.Builder builder) {
        try {
            // 检查最近1小时的推送记录
            Timestamp oneHourAgo = Timestamp.valueOf(LocalDateTime.now().minus(1, ChronoUnit.HOURS));

            // 统计最近1小时的推送记录
            long recentRecordCount = pushRecordDao.count(
                new LambdaQueryWrapper<DpPushRecord>()
                    .ge(DpPushRecord::getStartTime, oneHourAgo)
            );

            // 统计成功的推送记录
            long successRecordCount = pushRecordDao.count(
                new LambdaQueryWrapper<DpPushRecord>()
                    .ge(DpPushRecord::getStartTime, oneHourAgo)
                    .eq(DpPushRecord::getStatus, DataPushConstants.RECORD_STATUS_SUCCESS)
            );

            // 统计失败的推送记录
            long failedRecordCount = pushRecordDao.count(
                new LambdaQueryWrapper<DpPushRecord>()
                    .ge(DpPushRecord::getStartTime, oneHourAgo)
                    .eq(DpPushRecord::getStatus, DataPushConstants.RECORD_STATUS_FAILED)
            );

            // 计算成功率
            double successRate = recentRecordCount > 0 ?
                (double) successRecordCount / recentRecordCount * 100 : 100.0;

            builder.withDetail("records.recent.total", recentRecordCount)
                   .withDetail("records.recent.success", successRecordCount)
                   .withDetail("records.recent.failed", failedRecordCount)
                   .withDetail("records.recent.successRate", String.format("%.2f%%", successRate));

            // 如果成功率低于80%，标记为DOWN
            if (successRate < 80.0 && recentRecordCount > 0) {
                builder.down().withDetail("reason", "推送成功率过低: " + String.format("%.2f%%", successRate));
            }

        } catch (Exception e) {
            log.warn("检查推送记录状态失败", e);
            builder.withDetail("records.error", e.getMessage());
        }
    }

    /**
     * 检查系统负载
     */
    private void checkSystemLoad(Health.Builder builder) {
        try {
            Runtime runtime = Runtime.getRuntime();

            // 内存使用情况
            long totalMemory = runtime.totalMemory();
            long freeMemory = runtime.freeMemory();
            long usedMemory = totalMemory - freeMemory;
            double memoryUsagePercent = (double) usedMemory / totalMemory * 100;

            builder.withDetail("system.memory.total", formatBytes(totalMemory))
                   .withDetail("system.memory.used", formatBytes(usedMemory))
                   .withDetail("system.memory.free", formatBytes(freeMemory))
                   .withDetail("system.memory.usagePercent", String.format("%.2f%%", memoryUsagePercent));

            // CPU核心数
            int availableProcessors = runtime.availableProcessors();
            builder.withDetail("system.cpu.cores", availableProcessors);

            // 如果内存使用率超过90%，标记为DOWN
            if (memoryUsagePercent > 90.0) {
                builder.down().withDetail("reason", "内存使用率过高: " + String.format("%.2f%%", memoryUsagePercent));
            }

        } catch (Exception e) {
            log.warn("检查系统负载失败", e);
            builder.withDetail("system.error", e.getMessage());
        }
    }

    /**
     * 格式化字节数
     */
    private String formatBytes(long bytes) {
        if (bytes < 1024) return bytes + " B";
        if (bytes < 1024 * 1024) return String.format("%.2f KB", bytes / 1024.0);
        if (bytes < 1024 * 1024 * 1024) return String.format("%.2f MB", bytes / (1024.0 * 1024));
        return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
    }
}
